package org.linlinjava.litemall.db.service;

import com.github.pagehelper.PageHelper;
import org.linlinjava.litemall.db.dao.LitemallActivityGrouponMapper;
import org.linlinjava.litemall.db.dao.LitemallActivityMapper;
import org.linlinjava.litemall.db.dao.LitemallActivityRulesMapper;
import org.linlinjava.litemall.db.dao.LitemallStatisticsMapper;
import org.linlinjava.litemall.db.domain.*;
import org.linlinjava.litemall.db.util.CommonUtils;
import org.linlinjava.litemall.db.util.TimeUtils;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import javax.annotation.Resource;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

@Service
public class LitemallActivityService {
    @Resource
    private LitemallActivityMapper activityMapper;
    @Resource
    private LitemallActivityRulesMapper activityRulesMapper;
    @Resource
    private LitemallActivityGrouponMapper activityGrouponMapper;
    @Resource
    private LitemallStatisticsMapper statisticsMapper;

    public List<LitemallActivity> pageQueryActivity(String title, String startTime, String endTime, LitemallAdmin admin, Integer page, Integer limit, String sort, String order) {
        LitemallActivityExample example = new LitemallActivityExample();
        LitemallActivityExample.Criteria criteria = example.createCriteria();

        if (!StringUtils.isEmpty(title)) {
            criteria.andTitleLike("%" + title + "%");
        }
        if (!StringUtils.isEmpty(startTime) && !StringUtils.isEmpty(endTime)) {
            criteria.andEndTimeBetween(LocalDateTime.parse(startTime, DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")), LocalDateTime.parse(endTime, DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
        }
        if (admin != null) {
            criteria.andAddByEqualTo(admin.getId().toString());
        }
        criteria.andDeletedEqualTo(LitemallActivity.NOT_DELETED);

        if (!StringUtils.isEmpty(sort) && !StringUtils.isEmpty(order)) {
            example.setOrderByClause(sort + " " + order);
        }
        PageHelper.startPage(page, limit);
        return activityMapper.selectByExample(example);
    }

    public List<LitemallActivity> queryByState(List<Byte> states) {
        LitemallActivityExample example = new LitemallActivityExample();
        example.or().andStateIn(states).andDeletedEqualTo(LitemallActivity.NOT_DELETED);
        return activityMapper.selectByExample(example);
    }

    public void addActivity(LitemallActivity entity, LitemallAdmin admin) {
        entity.setAddBy(admin.getId().toString());
        entity.setUpdateBy(admin.getId().toString());
        entity.setAddTime(LocalDateTime.now());
        entity.setUpdateTime(LocalDateTime.now());
        activityMapper.insertSelective(entity);
    }

    public int updateActivityById(LitemallActivity activity, LitemallAdmin admin) {
        activity.setUpdateTime(LocalDateTime.now());
        activity.setUpdateBy(admin == null ? "任务计划" : admin.getId().toString());
        LitemallActivityExample example = new LitemallActivityExample();
        example.or().andIdEqualTo(activity.getId());
        return activityMapper.updateByExampleSelective(activity, example);
    }

    public LitemallActivity queryById(Integer id) {
        return activityMapper.selectByPrimaryKey(id);
    }

    public LitemallActivity queryActivity(Integer id, LitemallAdmin admin) {
        LitemallActivityExample example = new LitemallActivityExample();
        LitemallActivityExample.Criteria criteria = example.createCriteria();
        criteria.andIdEqualTo(id);
        criteria.andDeletedEqualTo(LitemallActivity.NOT_DELETED);
        if (admin != null) {
            criteria.andAddByEqualTo(admin.getId().toString());
        }
        return activityMapper.selectOneByExample(example);
    }

    public boolean checkActivityExistByTitle(String title) {
        LitemallActivityExample example = new LitemallActivityExample();
        example.or().andTitleEqualTo(title).andDeletedEqualTo(LitemallActivity.NOT_DELETED);
        return activityMapper.countByExample(example) != 0;
    }

    public List<LitemallActivityGroupon> queryActivityGroupon(List<Integer> activityIds) {
        LitemallActivityGrouponExample example = new LitemallActivityGrouponExample();
        example.or().andActivityIdIn(activityIds).andDeletedEqualTo(LitemallActivityGroupon.NOT_DELETED);
        return activityGrouponMapper.selectByExample(example);
    }

    public int updateActivityGrouponById(LitemallActivityGroupon activityGroupon) {
        activityGroupon.setUpdateTime(LocalDateTime.now());
        LitemallActivityGrouponExample example = new LitemallActivityGrouponExample();
        example.or().andIdEqualTo(activityGroupon.getId());
        return activityGrouponMapper.updateByExampleSelective(activityGroupon, example);
    }

    public List<LitemallActivityRules> queryActivityRules(List<Integer> activityIds) {
        LitemallActivityRulesExample example = new LitemallActivityRulesExample();
        example.or().andActivityIdIn(activityIds).andDeletedEqualTo(LitemallActivityRules.NOT_DELETED);
        return activityRulesMapper.selectByExample(example);
    }

    public void batchSaveOrUpdateStatistics(List<LitemallStatistics> list) {
        // 1.今天是否已经有记录数据统计（如果数据统计今天有变动就会有记录）
        List<Map<String, Object>> params = list.stream()
                .filter(CommonUtils.distinctByKey(it -> it.getRelType() + it.getRelId()))
                .map(it -> {
                    Map<String, Object> map = new HashMap<>(16);
                    map.put("relType", it.getRelType());
                    map.put("relId", it.getRelId());
                    map.put("startTime", TimeUtils.getDateMin(LocalDateTime.now()));
                    map.put("endTime", TimeUtils.getDateMax(LocalDateTime.now()));
                    return map;
                }).collect(Collectors.toList());

        List<LitemallStatistics> entities = statisticsMapper.findByParams(params);

        // 2.今天暂无记录，根据离今天之前最近一天的统计数据与今天的数据是否发生变动，变动则对今天数据进行新增
        if (CollectionUtils.isEmpty(entities)) {
            // 新增要对所有类型(bType)都新增
            Set<Integer> insertRelIds = new HashSet<>();
            for (LitemallStatistics param : list) {
                Map<String, Object> map = new HashMap<>(16);
                map.put("relType", param.getRelType());
                map.put("relId", param.getRelId());
                map.put("bType", param.getbType());
                map.put("addTime", TimeUtils.getDateMin(LocalDateTime.now()));
                LitemallStatistics recent = statisticsMapper.findRecent(map);
                // 过往都没有记录，新增
                if (recent == null) {
                    insertRelIds.add(param.getRelId());
                }
                // 过往有记录，比较统计数如果有增加的就新增今天的数据
                else if (recent.getCount() < param.getCount()) {
                    insertRelIds.add(param.getRelId());
                }
                // 缓存被清空（1.遇到问题  2.活动未到期但主动清空），DB的数一定大于缓存的数
                // 统计时两个数每次都相加
                else if (recent.getCount() > param.getCount()) {
                    param.setCount(recent.getCount() + param.getCount());
                    insertRelIds.add(param.getRelId());
                }
                // 过往有记录，但统计数没有发生变化
                else {
                    // 不新增
                }
            }
            for (LitemallStatistics param : list) {
                if (insertRelIds.contains(param.getRelId())) {
                    param.setUpdateTime(LocalDateTime.now());
                    param.setAddTime(LocalDateTime.now());
                    statisticsMapper.insertSelective(param);
                }
            }
        }
        // 3.今天有记录，更新当天数据
        else {
            Map<String, LitemallStatistics> statMap = entities
                    .stream()
                    .collect(Collectors.toMap(
                            it -> it.getRelType() + "," + it.getRelId().toString() + "," + it.getbType(),
                            Function.identity()));

            for (LitemallStatistics param : list) {
                if (statMap.containsKey(param.getRelType() + "," + param.getRelId().toString() + "," + param.getbType())) {
                    LitemallStatistics entity = statMap.get(param.getRelType() + "," + param.getRelId().toString() + "," + param.getbType());
                    // 统计数有增加才更新
                    if (entity.getCount() < param.getCount()) {
                        entity.setCount(param.getCount());
                        entity.setUpdateTime(LocalDateTime.now());
                        LitemallStatisticsExample example = new LitemallStatisticsExample();
                        example.or().andIdEqualTo(entity.getId());
                        statisticsMapper.updateByExampleSelective(entity, example);
                    }
                    // 缓存被清空（1.遇到问题  2.活动未到期但主动清空），DB的数一定大于缓存的数
                    // 统计时两个数每次都相加
                    else if (entity.getCount() > param.getCount()) {
                        entity.setCount(entity.getCount() + param.getCount());
                        entity.setUpdateTime(LocalDateTime.now());
                        LitemallStatisticsExample example = new LitemallStatisticsExample();
                        example.or().andIdEqualTo(entity.getId());
                        statisticsMapper.updateByExampleSelective(entity, example);
                    }
                }
            }
        }

    }


    public List<LitemallStatistics> queryStatistics(Byte relType, Integer relId, Byte bType) {
        if (relId == null) {
            return Collections.emptyList();
        }
        LitemallStatisticsExample example = new LitemallStatisticsExample();
        LitemallStatisticsExample.Criteria criteria = example.createCriteria();
        if (relType != null) {
            criteria.andRelTypeEqualTo(relType);
        }
        criteria.andRelIdEqualTo(relId);
        if (bType != null) {
            criteria.andBTypeEqualTo(bType);
        }
        return statisticsMapper.selectByExample(example);
    }

    public LitemallActivityGroupon findByOrderId(Integer orderId){
        if (orderId == null) {
            return null;
        }
        LitemallActivityGrouponExample example = new LitemallActivityGrouponExample();
        example.or().andOrderIdEqualTo(orderId).andDeletedEqualTo(LitemallActivityGroupon.NOT_DELETED);
        return activityGrouponMapper.selectOneByExample(example);
    }

}
